package com.todo.event.activity.application.core.eventflow;

import com.alibaba.fastjson.JSONObject;
import com.todo.common.common.exception.BizException;
import com.todo.event.activity.application.entity.bo.EventDecisionBO;
import com.todo.event.activity.application.entity.bo.EventDetailBO;
import com.todo.event.activity.application.entity.context.DecisionExecuteContext;
import com.todo.event.activity.application.entity.model.DecisionRuleResultModel;
import com.todo.event.activity.application.entity.model.EventHbaseDataModel;
import com.todo.event.activity.application.entity.model.EventInfoModel;
import com.todo.event.activity.application.entity.model.SucceedDecisionModel;
import com.todo.event.activity.application.service.EventDecisionService;
import com.todo.event.activity.application.service.EventDetailService;
import com.todo.event.activity.application.service.impl.DecisionDataService;
import com.todo.event.activity.application.service.impl.EventDataService;
import com.todo.event.activity.application.util.EventActivityUtil;
import com.todo.event.activity.application.util.EventHBaseUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author azhebuxing
 * @date 2025/1/9 10:19
 * @description
 */
@Slf4j
@Component
public class DecisionExecute {

    @Resource
    private EventDetailService eventDetailService;
    @Resource
    private EventDecisionService eventDecisionService;
    @Resource
    private EventHBaseUtil eventHBaseUtil;
    @Resource
    private EventDataService eventDataService;
    @Resource
    private DecisionDataService decisionDataService;


    public Boolean execute(DecisionExecuteContext context) {
        if (context == null || !context.baseCheck()) {
            log.warn("DecisionExecute#execute 决策执行完成，数据异常，默认执行成功 content:【{}】", JSONObject.toJSONString(context));
            return true;
        }
        //1、线判断是否存在相关配置事件/接口
        List<EventDetailBO> eventDetailBOList = queryEventConfByTopicName(context.getTopicName(), context.getTag());
        if (CollectionUtils.isEmpty(eventDetailBOList)) {
            log.warn("DecisionExecute#execute 决策执行完成，不存在相关配置事件/接口，默认执行成功 context:【{}】", JSONObject.toJSONString(context));
            return true;
        }

        List<String> evnetCodeList = eventDetailBOList.stream().map(EventDetailBO::getEventCode).collect(Collectors.toList());

        Map<String/*eventCode*/, EventInfoModel> executeModelMap = new HashMap<>();
        //2、数据转化
        for (EventDetailBO eventDetailBO : eventDetailBOList) {
            try {
                EventInfoModel eventInfoModel = eventDataService.buildAndeGetExecuteModel(eventDetailBO, context.getPayload());
                if (eventInfoModel == null) {
                    continue;
                }
                executeModelMap.put(eventInfoModel.getEventCode(), eventInfoModel);
            } catch (BizException ex) {
                log.warn("DecisionExecute#execute 决策执行完成遇到业务异常，默认当前事件不通过，eventDetailBO:【{}】", JSONObject.toJSONString(eventDetailBO), ex);
            } catch (Exception ex) {
                log.error("DecisionExecute#execute 决策执行失败，数据转化失败，eventDetailBO:【{}】", JSONObject.toJSONString(eventDetailBO), ex);
            }
        }

        if (MapUtils.isEmpty(executeModelMap)) {
            log.warn("DecisionExecute#execute 决策执行完成，不存在相关数据成功的配置事件/接口，默认执行成功 context:【{}】", JSONObject.toJSONString(context));
            return true;
        }

        List<SucceedDecisionModel> succeedDecisionModelList = new ArrayList<>();
        List<EventDecisionBO> failedDecisionModelList = new ArrayList<>();

        List<EventDecisionBO> singleDecisionList = eventDecisionService.querySingleEventListByCodeList(evnetCodeList);
        List<EventDecisionBO> multipleDecisionList = eventDecisionService.queryMultipleEventListByCodeList(evnetCodeList);
        if (CollectionUtils.isEmpty(singleDecisionList) && CollectionUtils.isEmpty(multipleDecisionList)) {
            log.warn("DecisionExecute#execute 决策执行完成，不存在相关配置事件/接口，默认执行成功 context:【{}】", JSONObject.toJSONString(context));
            return true;
        }


        //3、单事件决策执行
        if (CollectionUtils.isNotEmpty(singleDecisionList)) {
            executeSingleDecisionList(executeModelMap, singleDecisionList, succeedDecisionModelList, failedDecisionModelList);
        }

        //4、多事件决策执行
        if (CollectionUtils.isNotEmpty(multipleDecisionList)) {
            executeMultipleDecisionList(evnetCodeList, executeModelMap, multipleDecisionList, succeedDecisionModelList, failedDecisionModelList);
        }

        //5、统一决策消息发送
        sendSucceedDecisionMessage(succeedDecisionModelList);

        return true;
    }

    /**
     * 多事件决策列表执行
     *
     * @param evnetCodeList
     * @param executeModelMap
     * @param multipleDecisionList
     * @param succeedDecisionModelList
     * @param failedDecisionModelList
     */
    private void executeMultipleDecisionList(List<String> evnetCodeList, Map<String, EventInfoModel> executeModelMap, List<EventDecisionBO> multipleDecisionList, List<SucceedDecisionModel> succeedDecisionModelList, List<EventDecisionBO> failedDecisionModelList) {
        List<EventDecisionBO> firstEventList = new ArrayList<>();
        List<EventDecisionBO> secondEventList = new ArrayList<>();
        //首先区分开我们需要处理的事件是在那个决策分类中
        preFillEventExecuteList(evnetCodeList, firstEventList, secondEventList, multipleDecisionList);

        //首事件处理
        if (CollectionUtils.isNotEmpty(firstEventList)) {
            for (EventDecisionBO eventDecisionBO : firstEventList) {
                //首事件无获取数据等逻辑
                Boolean executeResult = executeMultipleFirstDecision(executeModelMap.get(eventDecisionBO.getFirstEvent()), eventDecisionBO);
                if (!executeResult) {
                    failedDecisionModelList.add(eventDecisionBO);
                }
            }
        }

        //如果为次事件，则查询所有对应的数据，进行比对判断
        if (CollectionUtils.isNotEmpty(secondEventList)) {
            for (EventDecisionBO eventDecisionBO : secondEventList) {
                SucceedDecisionModel succeedDecisionModel = executeMultipleSecondDecision(executeModelMap.get(eventDecisionBO.getSecondEvent()), eventDecisionBO);
                if (succeedDecisionModel == null) {
                    failedDecisionModelList.add(eventDecisionBO);
                    continue;
                }
                succeedDecisionModelList.add(succeedDecisionModel);
            }
        }
    }

    /**
     * 单事件决策列表执行
     *
     * @param executeModelMap
     * @param singleDecisionList
     * @param succeedDecisionModelList
     * @param failedDecisionModelList
     */
    private void executeSingleDecisionList(Map<String/*eventCode*/, EventInfoModel> executeModelMap, List<EventDecisionBO> singleDecisionList, List<SucceedDecisionModel> succeedDecisionModelList, List<EventDecisionBO> failedDecisionModelList) {
        //单事件下判断首事件的规则是否满足即可，满足则添加至成功决策模型 / 不满足则不做处理
        for (EventDecisionBO eventDecisionBO : singleDecisionList) {
            EventInfoModel eventInfoModel = executeModelMap.get(eventDecisionBO.getFirstEvent());
            if (eventInfoModel == null) {
                continue;
            }
            DecisionRuleResultModel ruleCheck = decisionDataService.eventDecisionRuleCheck(eventDecisionBO.getFirstEventRule(), eventInfoModel.getNewPayload(), eventDecisionBO.getId(), eventInfoModel.getEventCode());
            if (!ruleCheck.getResult()) {
                log.warn("DecisionExecute#execute 决策执行完成，首事件规则校验失败， eventDecisionBO：【{}】ruleCheck：【{}】", JSONObject.toJSONString(eventDecisionBO), JSONObject.toJSONString(ruleCheck));
                failedDecisionModelList.add(eventDecisionBO);
                continue;
            }
            succeedDecisionModelList.add(buildSucceedDecisionModel(eventDecisionBO, eventInfoModel));
        }
    }

    /**
     * 多事件决策针对second事件具体执行逻辑
     *
     * @param eventInfoModel
     * @param eventDecisionBO
     * @return
     */
    private SucceedDecisionModel executeMultipleSecondDecision(EventInfoModel eventInfoModel, EventDecisionBO eventDecisionBO) {
        if (eventInfoModel == null) {
            return null;
        }
        //多事件情况下的次事件是否满足规则
        DecisionRuleResultModel ruleCheck = decisionDataService.eventDecisionRuleCheck(eventDecisionBO.getSecondEventRule(), eventInfoModel.getNewPayload(), eventDecisionBO.getId(), eventInfoModel.getEventCode());
        if (!ruleCheck.getResult()) {
            return null;
        }
        Long userId = EventActivityUtil.getUserIdByEventDecisionPayload(eventInfoModel.getNewPayload());
        List<EventHbaseDataModel> eventHbaseDataModels = eventHBaseUtil.queryEventDataListByUserId(userId, eventDecisionBO.getId());
        if (CollectionUtils.isEmpty(eventHbaseDataModels)) {
            log.warn("DecisionExecute#executeMultipleSecondDecision 多事件情况下次事件匹配失败，hbase数据为空，不存在关联数据，继续执行后续逻辑 decisionId:【{}】userId:【{}】，事件uk：【{}】", userId, eventDecisionBO.getId(), eventInfoModel.getUk());
            return null;
        }
        //使用唯一标识
        if (eventDecisionBO.getUseUnique() != null && eventDecisionBO.getUseUnique()) {
            for (EventHbaseDataModel eventHbaseDataModel : eventHbaseDataModels) {
                if (eventHbaseDataModel.getUk().equals(eventInfoModel.getUk())) {
                    //剔除当前hbase数据
                    eventHBaseUtil.removeEventData(eventHbaseDataModel);
                    return buildSucceedDecisionModel(eventDecisionBO, eventInfoModel);
                }
            }
        } else {
            //不实用唯一标识下，找到一条数据匹配即可List(0)剔除当前hbase数据
            EventHbaseDataModel eventHbaseDataModel = eventHbaseDataModels.get(0);
            eventHBaseUtil.removeEventData(eventHbaseDataModel);
            return buildSucceedDecisionModel(eventDecisionBO, eventInfoModel);
        }
        return null;
    }

    /**
     * 多事件决策针对first事件具体执行逻辑
     *
     * @param eventInfoModel
     * @param eventDecisionBO
     * @return
     */
    private Boolean executeMultipleFirstDecision(EventInfoModel eventInfoModel, EventDecisionBO eventDecisionBO) {
        if (eventInfoModel == null) {
            return false;
        }
        //多事件情况下的首事件是否满足规则
        DecisionRuleResultModel ruleCheck = decisionDataService.eventDecisionRuleCheck(eventDecisionBO.getFirstEventRule(), eventInfoModel.getNewPayload(), eventDecisionBO.getId(), eventInfoModel.getEventCode());
        if (!ruleCheck.getResult()) {
            return false;
        }
        EventHbaseDataModel eventHbaseDataModel = new EventHbaseDataModel();
        eventHbaseDataModel.setDecisionId(eventDecisionBO.getId());
        eventHbaseDataModel.setUserId(EventActivityUtil.getUserIdByEventDecisionPayload(eventInfoModel.getNewPayload()));
        eventHbaseDataModel.setUk(eventInfoModel.getUk());
        eventHbaseDataModel.setSaveValue(eventInfoModel.getNewPayload());
        eventHbaseDataModel.setTtl(MinTimTransferMS(eventDecisionBO.getIntervalTime()));
        eventHBaseUtil.insertEventData(eventHbaseDataModel);
        return true;
    }

    /**
     * 执行前数据校验区分
     *
     * @param evnetCodeList
     * @param firstEventList
     * @param secondEventList
     * @param multipleDecisionList
     */
    private void preFillEventExecuteList(List<String> evnetCodeList, List<EventDecisionBO> firstEventList, List<EventDecisionBO> secondEventList, List<EventDecisionBO> multipleDecisionList) {
        for (EventDecisionBO eventDecisionBO : multipleDecisionList) {
            for (String executeEvent : evnetCodeList) {
                if (eventDecisionBO.getFirstEvent().equals(executeEvent)) {
                    firstEventList.add(eventDecisionBO);
                } else {
                    secondEventList.add(eventDecisionBO);
                }
            }
        }
    }

    /**
     * 执行成功决策消息发送
     *
     * @param succeedDecisionModelList
     */
    private void sendSucceedDecisionMessage(List<SucceedDecisionModel> succeedDecisionModelList) {
        if (CollectionUtils.isNotEmpty(succeedDecisionModelList)) {
            for (SucceedDecisionModel succeedDecisionModel : succeedDecisionModelList) {
                log.info("DecisionExecute#sendSucceedDecisionMessage 发送决策消息成功，succeedDecisionModel:【{}】", JSONObject.toJSONString(succeedDecisionModel));
            }
        }
    }

    /**
     * 构建基础通过成功决策模型
     *
     * @param eventDecisionBO
     * @param eventInfoModel
     * @return
     */
    private SucceedDecisionModel buildSucceedDecisionModel(EventDecisionBO eventDecisionBO, EventInfoModel eventInfoModel) {
        SucceedDecisionModel succeedDecisionModel = new SucceedDecisionModel();
        succeedDecisionModel.setDecisionId(eventDecisionBO.getId());
        succeedDecisionModel.setName(eventDecisionBO.getName());
        succeedDecisionModel.setQueueType(eventInfoModel.getQueueType());
        succeedDecisionModel.setUk(eventInfoModel.getUk());
        succeedDecisionModel.setPayload(eventInfoModel.getNewPayload());
        return succeedDecisionModel;
    }

    private Long MinTimTransferMS(Integer intervalTime) {
        if (intervalTime == null) {
            return 0L;
        }
        return (long) (intervalTime * 60 * 1000);
    }

    /**
     * 根据topicName和tag查询事件配置
     *
     * @param topicName
     * @param tag
     * @return
     */
    private List<EventDetailBO> queryEventConfByTopicName(String topicName, String tag) {
        List<EventDetailBO> eventDetailBOList = eventDetailService.queryEventDetailByTopic(topicName, tag);
        return eventDetailBOList;
    }

}
